import json
from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi import Request, Response, HTTPException, status
from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html, get_swagger_ui_oauth2_redirect_html
from app.api.v1 import auth, users, health, files, chat, medical_records, report_classifications, dicts, capsule
from app.core.config import settings
from app.core.database import init_db
from app.core.logging_config import LogConfig, get_logger
from app.utils.redis_client import redis_client
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
from fastapi.staticfiles import StaticFiles
from app.utils.exceptions import (
 AppException
)

# 初始化日志配置
log_config = LogConfig(
    log_level=settings.LOG_LEVEL,
    log_file=settings.LOG_FILE,
    max_file_size=settings.LOG_MAX_SIZE,
    backup_count=settings.LOG_BACKUP_COUNT,
    enable_console=settings.LOG_ENABLE_CONSOLE,
    enable_file=settings.LOG_ENABLE_FILE
)
log_config.setup_logging()

# 获取日志器
logger = get_logger(__name__)


@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    Application lifespan events
    """
    # Startup
    logger.info("Starting up FastAPI application...")

    # Initialize database
    await init_db()
    logger.info("Database initialized")

    # Initialize Redis
    await redis_client.init_redis_pool()
    logger.info("Redis connection pool initialized")

    # Initialize Capsule Service
    from app.services.capsule_service import capsule_service
    await capsule_service.initialize()
    logger.info("Capsule service initialized")

    yield

    # Shutdown
    logger.info("Shutting down FastAPI application...")

    # Close Redis connection
    await redis_client.close_redis_pool()
    logger.info("Redis connection pool closed")


# Create FastAPI app with lifespan events
app = FastAPI(
    title=settings.PROJECT_NAME,
    version=settings.VERSION,
    openapi_url=f"{settings.API_V1_STR}/openapi.json",
    docs_url=None,
    redoc_url=None,
    lifespan=lifespan,
)

# Set up CORS
if settings.CORS_ORIGINS:
    app.add_middleware(
        CORSMiddleware,
        allow_origins=settings.CORS_ORIGINS,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )


# 添加这一个统一的处理器
@app.exception_handler(AppException)
async def app_exception_handler(request: Request, exc: AppException):
    """
    统一处理所有自定义的业务异常。
    """
    return JSONResponse(
        status_code=200,
        content={
            "code": exc.code,
            "message": exc.message,
            "data": None,
        }
    )


# 处理 FastAPI 的校验错误
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    # 将错误信息转换为可序列化的格式
    
    return JSONResponse(
        status_code=200,
        content={
            "code": 422,
            "message": "请求参数校验失败",
            "data": exc.errors()[0].get("msg"),
        },
    )


# 处理 FastAPI 内部的 HTTPException
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
    return JSONResponse(
        status_code=200,
        content={
            "code": exc.status_code,  # 简单派生一个业务码
            "message": exc.detail,
            "data": None
        }
    )


# Include routers
app.include_router(
    auth.router,
    prefix=f"{settings.API_V1_STR}/auth",
    tags=["Authentication"]
)

app.include_router(
    users.router,
    prefix=f"{settings.API_V1_STR}/users",
    tags=["Users"]
)

app.include_router(
    health.router,
    prefix=f"{settings.API_V1_STR}/health",
    tags=["Health"]
)

app.include_router(
    files.router,
    prefix=f"{settings.API_V1_STR}/files",
    tags=["Files"]
)

app.include_router(
    chat.router,
    prefix=f"{settings.API_V1_STR}/chat",
    tags=["Chat"]
)

app.include_router(
    medical_records.router,
    prefix=f"{settings.API_V1_STR}/medical-records",
    tags=["Medical Records"]
)

app.include_router(
    report_classifications.router,
    prefix=f"{settings.API_V1_STR}/report-classifications",
    tags=["Report Classifications"]
)

app.include_router(
    dicts.router,
    prefix=f"{settings.API_V1_STR}/dicts",
    tags=["Dictionary"]
)

app.include_router(
    capsule.router,
    prefix=f"{settings.API_V1_STR}/capsule",
    tags=["Capsule System"]
)

# 获取当前文件所在目录
BASE_DIR = Path(__file__).resolve().parent
STATIC_DIR = BASE_DIR / "static"

app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")


@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url=app.openapi_url,
        title=app.title + " - Swagger UI",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        swagger_js_url="/static/swagger-ui-bundle.js",
        swagger_css_url="/static/swagger-ui.css",
    )


@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
    return get_swagger_ui_oauth2_redirect_html()


@app.get("/redoc", include_in_schema=False)
async def redoc_html():
    return get_redoc_html(
        openapi_url=app.openapi_url,
        title=app.title + " - ReDoc",
        redoc_js_url="/static/redoc.standalone.js",
    )


# Root endpoint
@app.get("/")
async def root():
    return {
        "message": f"Welcome to {settings.PROJECT_NAME}",
        "version": settings.VERSION,
        "docs_url": f"{settings.API_V1_STR}/docs",
    }


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(
        "app.main:app",
        host="0.0.0.0",
        port=8000,
        reload=settings.DEBUG
    )
